﻿using Discount.Grpc.Data;
using Discount.Grpc.Models;
using Grpc.Core;
using Mapster;
using MassTransit;
using Microsoft.EntityFrameworkCore;
using System.Reflection.Metadata;

namespace Discount.Grpc.Services;

public class DiscountService
    (DiscountContext dbContext, ILogger<DiscountService> logger)
    : DiscountProtoService.DiscountProtoServiceBase
{    
    public override async Task<CouponModel> GetDiscount(GetDiscountRequest request, ServerCallContext context)
    {
        var coupon = await dbContext
            .Coupons
            .FirstOrDefaultAsync(x => x.ProductName == request.ProductName);

        if (coupon is null)
            coupon = new Coupon { ProductName = "No Discount", Amount = 0, Description = "No Discount Desc" };

        logger.LogInformation("Discount is retrieved for ProductName : {productName}, Amount : {amount}", coupon.ProductName, coupon.Amount);

        var couponModel = coupon.Adapt<CouponModel>();
        return couponModel;
    }

    public override async Task<CouponModel> CreateDiscount(CreateDiscountRequest request, ServerCallContext context)
    {
        var coupon = request.Coupon.Adapt<Coupon>();
        if (coupon is null)
            throw new RpcException(new Status(StatusCode.InvalidArgument, "Invalid request object."));

        dbContext.Coupons.Add(coupon);
        await dbContext.SaveChangesAsync();

        logger.LogInformation("Discount is successfully created. ProductName : {ProductName}", coupon.ProductName);

        var couponModel = coupon.Adapt<CouponModel>();
        return couponModel;
    }


    public override async Task<CouponModel> UpdateDiscount(UpdateDiscountRequest request, ServerCallContext context)
    {
        var coupon = request.Coupon.Adapt<Coupon>();
        if (coupon is null)
            throw new RpcException(new Status(StatusCode.InvalidArgument, "Invalid request object."));

        dbContext.Coupons.Update(coupon);
        await dbContext.SaveChangesAsync();

        logger.LogInformation("Discount is successfully updated. ProductName : {ProductName}", coupon.ProductName);

        var couponModel = coupon.Adapt<CouponModel>();
        return couponModel;
    }

    public override async Task<DeleteDiscountResponse> DeleteDiscount(DeleteDiscountRequest request, ServerCallContext context)
    {
        var coupon = await dbContext
            .Coupons
            .FirstOrDefaultAsync(x => x.ProductName == request.ProductName);

        if (coupon is null)
            throw new RpcException(new Status(StatusCode.NotFound, $"Discount with ProductName={request.ProductName} is not found."));

        dbContext.Coupons.Remove(coupon);
        await dbContext.SaveChangesAsync();

        logger.LogInformation("Discount is successfully deleted. ProductName : {ProductName}", request.ProductName);

        return new DeleteDiscountResponse { Success = true };
    }

    public async override Task<LockDiscountResponse> LockDiscount(LockDiscountRequest request, ServerCallContext context)
    {
        return await DiscountEx.Handle(request, dbContext);
    }
    
}

public class DiscountEx 
{
    public async static Task<LockDiscountResponse> Handle(LockDiscountRequest request, DiscountContext dbContext) 
    {
        if (request == null || request.CouponId == 0 || string.IsNullOrEmpty(request.OrderId) || request.Qty <= 0)
        {
            throw new RpcException(new Status(StatusCode.InvalidArgument, "Invalid request object."));
        }
        var coupon = await dbContext
            .Coupons
            .FirstOrDefaultAsync(x => x.Id == request.CouponId);
        if (coupon is null)
        {
            throw new RpcException(new Status(StatusCode.InvalidArgument, "Coupon Is not Avaliable!"));
        }
        coupon.LockedQuantity += request.Qty;
        coupon.StockQuantity -= request.Qty;
        if (coupon.StockQuantity <= 0)
        {
            throw new RpcException(new Status(StatusCode.InvalidArgument, "Coupon Is not Avaliable!"));
        }

        dbContext.Coupons.Update(coupon);
        var record = new CouponLockRecord
        {
            CouponId = request.CouponId,
            Status = 0,
            CreatedTime = DateTime.Now,
            OrderId = Guid.Parse(request.OrderId),
            Qty = request.Qty,
        };
        dbContext.CouponLockRecords.Add(record);


        await dbContext.SaveChangesAsync();


        return new LockDiscountResponse
        {
            IsOk = true,
            RecordId = 1
        };
    }
}
